package jp.peach_boys.sandbox.slim3.domain;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import jp.peach_boys.sandbox.slim3.dto.RestaurantInfo;
import jp.peach_boys.sandbox.slim3.entity.Image;
import jp.peach_boys.sandbox.slim3.entity.Memo;

public class TabelogApi {
    private static final String BASE_URL =
        "http://api.tabelog.com/Ver2.1/RestaurantSearch/?Key=";
    private final String apiAccessKey;
    private final Map<Todoufuken, Map<Integer,Document>> cache;

    public TabelogApi(String apiAccessKey){
        this.apiAccessKey = apiAccessKey;
        cache = new HashMap<Todoufuken, Map<Integer,Document>>();
    }
    
    public List<RestaurantInfo> getRestaurantInfos(Todoufuken todoufuken, Integer pageNo) throws IOException, ParserConfigurationException, SAXException, XPathExpressionException {
        Document doc = accessApi(todoufuken, pageNo == null ? 1 : pageNo);
        // XPathを使ってXMLからRestaulantの配列取得
        RestaurantInfo[] restaurants = getRestaurantList(doc);
        return Arrays.asList(restaurants);
    }

    private Document accessApi(Todoufuken todoufuken, Integer pageNo)
            throws MalformedURLException, IOException,
            UnsupportedEncodingException, ParserConfigurationException,
            SAXException {
        Document doc;
        if(cache.get(todoufuken) == null){
            cache.put(todoufuken, new HashMap<Integer, Document>());
        }
        if(cache.get(todoufuken).get(pageNo) == null){
            // 食べログのレストラン情報XMLのstream取得
            InputStream stream = getXmlStream(todoufuken, pageNo);
            // stream -> Document へのパース
            doc = parseXML(stream);
            // 何回もアクセスさせないようにキャッシュb
            cache.get(todoufuken).put(pageNo, doc);
        }
        return cache.get(todoufuken).get(pageNo);
    }

    private InputStream getXmlStream(Todoufuken todofuken, int page)
            throws MalformedURLException, IOException,
            UnsupportedEncodingException {
        URL url = new URL(BASE_URL + apiAccessKey + "&Prefecture=" + todofuken.getKey() + "&PageNum=" + page);
        System.out.println(url.toString());
        return url.openStream();
    }

    private Document parseXML(InputStream stream)
            throws ParserConfigurationException, SAXException, IOException {
        DocumentBuilderFactory docFactory =
            DocumentBuilderFactory.newInstance();
        docFactory.setNamespaceAware(true);
        DocumentBuilder builder = docFactory.newDocumentBuilder();
        Document doc = builder.parse(new InputSource(stream));
        return doc;
    }

    private RestaurantInfo[] getRestaurantList(Document doc)
            throws ParserConfigurationException, SAXException, IOException,
            XPathExpressionException {
        XPath xpath = XPathFactory.newInstance().newXPath();
        NodeList nodes =
            (NodeList) xpath.evaluate(
                "//RestaurantInfo/Item",
                doc,
                XPathConstants.NODESET);

        RestaurantInfo[] restaurants = new RestaurantInfo[nodes.getLength()];
        for (int i = 0; i < nodes.getLength(); i++) {
            RestaurantInfo info = new RestaurantInfo();
            NodeList attrs = nodes.item(i).getChildNodes();
            for (int j = 0; j < attrs.getLength(); j++) {
                Node attribute = attrs.item(j);
                if (attribute.getNodeName().equals("RestaurantName")) {
                    info.setRestaurantName(attribute.getTextContent());
                } else if (attribute.getNodeName().equals("TabelogUrl")) {
                    info.setUrl(attribute.getTextContent());
                } else if (attribute.getNodeName().equals("Rcd")) {
                    String rcd = attribute.getTextContent();
                    info.setRcd(rcd);

                    // 登録されているメモ情報の取得
                    Memo memo = Memo.getMemo(rcd);
                    if (memo != null) {
                        info.setMemo(memo.getMemo());
                    }

                    // 登録されている写真の取得
                    Image image = Image.getImageByRcd(rcd);
                    if (image != null) {
                        info.setImageName(image.getFilename());
                    }

                }
            }
            restaurants[i] = info;
        }
        return restaurants;
    }
    public int getNumOfRestraunt(Todoufuken todofuken)
        throws XPathExpressionException, MalformedURLException, UnsupportedEncodingException, IOException, ParserConfigurationException, SAXException {
        XPath xpath = XPathFactory.newInstance().newXPath();
        NodeList numNodes = (NodeList) xpath.evaluate("//RestaurantInfo/NumOfResult", accessApi(todofuken, 1), XPathConstants.NODESET);
        return Integer.parseInt(numNodes.item(0).getTextContent());
    }

}
